#ifndef __MCS__OPERATOR_FUNCTION_COLLECTION__HPP
#define __MCS__OPERATOR_FUNCTION_COLLECTION__HPP

#include "FunctionFactory.hpp"

/// Collection of functions that implement build-in operators
class OperatorFunctionCollection : public FunctionCollection
{
public:
	virtual void registerFunctions(FunctionFactory * factory)
	{
		factory->insertFunction("operator+", &operatorAdd);
		factory->insertFunction("operator-", &operatorSub);
		factory->insertFunction("operator*", &operatorMul);
		factory->insertFunction("operator/", &operatorDiv);
		factory->insertFunction("operator%", &operatorMod);
		factory->insertFunction("operator|", &operatorOr);
		factory->insertFunction("operator&", &operatorAnd);
		factory->insertFunction("operator^", &operatorXor);
		factory->insertFunction("operator<<", &operatorShL);
		factory->insertFunction("operator>>", &operatorShR);
		factory->insertFunction("operator~", &operatorInv);
		factory->insertFunction("operator-", &operatorNeg);
		factory->insertFunction("operator+", &operatorPos);
		factory->insertFunction("operator+", &operatorAddF);
		factory->insertFunction("operator-", &operatorSubF);
		factory->insertFunction("operator*", &operatorMulF);
		factory->insertFunction("operator/", &operatorDivF);
		factory->insertFunction("operator-", &operatorNegF);
		factory->insertFunction("operator+", &operatorPosF);
		factory->insertFunction("operator!", &operatorBoolNot);
		factory->insertFunction("operator&", &operatorBoolAnd);
		factory->insertFunction("operator|", &operatorBoolOr);
		factory->insertFunction("operator^", &operatorBoolXor);
		factory->insertFunction("operator<", &operatorCmpLNGE<int>);
		factory->insertFunction("operator>", &operatorCmpGNLE<int>);
		factory->insertFunction("operator==", &operatorCmpENLG<int>);
		factory->insertFunction("operator>=", &operatorCmpGENL<int>);
		factory->insertFunction("operator<=", &operatorCmpLENG<int>);
		factory->insertFunction("operator!=", &operatorCmpLGNE<int>);
		factory->insertFunction("operator$", &operatorConcat);
		factory->insertFunction("operator<", &operatorCmpLNGE<String const &>);
		factory->insertFunction("operator>", &operatorCmpGNLE<String const &>);
		factory->insertFunction("operator==", &operatorCmpENLG<String const &>);
		factory->insertFunction("operator>=", &operatorCmpGENL<String const &>);
		factory->insertFunction("operator<=", &operatorCmpLENG<String const &>);
		factory->insertFunction("operator!=", &operatorCmpLGNE<String const &>);
		factory->insertFunction("operator:=", &operatorAssign<bool>);
		factory->insertFunction("operator:=", &operatorAssign<int>);
		factory->insertFunction("operator:=", &operatorAssign<String const &>);
		factory->insertFunction("operator:=", &operatorAssign<double>);
		factory->insertFunction("operator+=", &operatorAdd);
		factory->insertFunction("operator-=", &operatorSub);
		factory->insertFunction("operator*=", &operatorMul);
		factory->insertFunction("operator/=", &operatorDiv);
		factory->insertFunction("operator%=", &operatorMod);
		factory->insertFunction("operator|=", &operatorOr);
		factory->insertFunction("operator&=", &operatorAnd);
		factory->insertFunction("operator^=", &operatorXor);
		factory->insertFunction("operator<<=", &operatorShL);
		factory->insertFunction("operator>>=", &operatorShR);
		factory->insertFunction("operator+=", &operatorAddF);
		factory->insertFunction("operator-=", &operatorSubF);
		factory->insertFunction("operator*=", &operatorMulF);
		factory->insertFunction("operator/=", &operatorDivF);
		factory->insertFunction("operator&=", &operatorBoolAnd);
		factory->insertFunction("operator|=", &operatorBoolOr);
		factory->insertFunction("operator^=", &operatorBoolXor);
		factory->insertFunction("operator$=", &operatorConcat);

		factory->insertFunction("iif", &functionIif<bool>);
		factory->insertFunction("iif", &functionIif<int>);
		factory->insertFunction("iif", &functionIif<String const &>);
		factory->insertFunction("iif", &functionIif<double>);
	}

	static int operatorAdd(int a, int b) { return a + b; }
	static int operatorSub(int a, int b) { return a - b; }
	static int operatorMul(int a, int b) { return a * b; }
	static int operatorDiv(int a, int b) { return a / b; }
	static int operatorMod(int a, int b) { return a % b; }
	static int operatorOr (int a, int b) { return a | b; }
	static int operatorAnd(int a, int b) { return a & b; }
	static int operatorXor(int a, int b) { return a ^ b; }
	static int operatorShL(int a, int b) { return a << b; }
	static int operatorShR(int a, int b) { return a >> b; }
	static int operatorInv(int a) { return ~a; }
	static int operatorNeg(int a) { return -a; }
	static int operatorPos(int a) { return +a; }

	static double operatorAddF(double a, double b) { return a + b; }
	static double operatorSubF(double a, double b) { return a - b; }
	static double operatorMulF(double a, double b) { return a * b; }
	static double operatorDivF(double a, double b) { return a / b; }
	static double operatorNegF(double a) { return -a; }
	static double operatorPosF(double a) { return +a; }

	static bool operatorBoolNot(bool a) { return !a; }
	static bool operatorBoolAnd(bool a, bool b) { return a && b; }
	static bool operatorBoolOr (bool a, bool b) { return a || b; }
	static bool operatorBoolXor(bool a, bool b) { return (a && !b) || (b && !a); }

	template<class T> static bool operatorCmpLNGE(T a, T b) { return a < b; }
	template<class T> static bool operatorCmpGNLE(T a, T b) { return a > b; }
	template<class T> static bool operatorCmpENLG(T a, T b) { return a == b; }
	template<class T> static bool operatorCmpGENL(T a, T b) { return a >= b; }
	template<class T> static bool operatorCmpLENG(T a, T b) { return a <= b; }
	template<class T> static bool operatorCmpLGNE(T a, T b) { return a != b; }

	template<class T> T static operatorAssign(T x, T y) { (void)x; return y; }

	static String operatorConcat(String const & s1, String const & s2) { return s1 + s2; }

	template<class T> static T functionIif(bool cond, T a, T b) { return cond ? a : b; }
};

#endif //__MCS__OPERATOR_FUNCTION_COLLECTION__HPP